home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / sound / ymdeltat.c < prev    next >
C/C++ Source or Header  |  2000-04-23  |  8KB  |  253 lines

  1. /*
  2. **
  3. ** File: ymdeltat.c
  4. **
  5. ** YAMAHA DELTA-T adpcm sound emulation subroutine
  6. ** used by fmopl.c(v0.36e-) and fm.c(v0.36c-)
  7. **
  8. ** Base program is YM2610 emulator by Hiromitsu Shioya.
  9. ** Written by Tatsuyuki Satoh
  10. **
  11. ** Version 0.36b
  12. **
  13. ** sound chips who has this unit
  14. **
  15. ** YM2608   OPNA
  16. ** YM2610/B OPNB
  17. ** Y8950    MSX AUDIO
  18. **
  19. **
  20. */
  21.  
  22. #ifndef YM_INLINE_BLOCK
  23.  
  24. #include "driver.h"
  25. #include "ymdeltat.h"
  26.  
  27. UINT8 *ym_deltat_memory;      /* memory pointer */
  28.  
  29. /* Forecast to next Forecast (rate = *8) */
  30. /* 1/8 , 3/8 , 5/8 , 7/8 , 9/8 , 11/8 , 13/8 , 15/8 */
  31. const INT32 ym_deltat_decode_tableB1[16] = {
  32.   1,   3,   5,   7,   9,  11,  13,  15,
  33.   -1,  -3,  -5,  -7,  -9, -11, -13, -15,
  34. };
  35. /* delta to next delta (rate= *64) */
  36. /* 0.9 , 0.9 , 0.9 , 0.9 , 1.2 , 1.6 , 2.0 , 2.4 */
  37. const INT32 ym_deltat_decode_tableB2[16] = {
  38.   57,  57,  57,  57, 77, 102, 128, 153,
  39.   57,  57,  57,  57, 77, 102, 128, 153
  40. };
  41.  
  42. /* DELTA-T-ADPCM write register */
  43. void YM_DELTAT_ADPCM_Write(YM_DELTAT *DELTAT,int r,int v)
  44. {
  45.     if(r>=0x10) return;
  46.     DELTAT->reg[r] = v; /* stock data */
  47.  
  48.     switch( r ){
  49.     case 0x00:    /* START,REC,MEMDATA,REPEAT,SPOFF,--,--,RESET */
  50. #if 0
  51.         case 0x60:    /* write buffer MEMORY from PCM data port */
  52.         case 0x20:    /* read  buffer MEMORY to   PCM data port */
  53. #endif
  54.         if( v&0x80 ){
  55.             DELTAT->portstate = v&0x90; /* start req,memory mode,repeat flag copy */
  56.             /**** start ADPCM ****/
  57.             DELTAT->volume_w_step = (double)DELTAT->volume * DELTAT->step / (1<<YM_DELTAT_SHIFT);
  58.             DELTAT->now_addr = (DELTAT->start)<<1;
  59.             DELTAT->now_step = (1<<YM_DELTAT_SHIFT)-DELTAT->step;
  60.             /*adpcm->adpcmm   = 0;*/
  61.             DELTAT->adpcmx   = 0;
  62.             DELTAT->adpcml   = 0;
  63.             DELTAT->adpcmd   = YM_DELTAT_DELTA_DEF;
  64.             DELTAT->next_leveling=0;
  65.             DELTAT->flag     = 1; /* start ADPCM */
  66.  
  67.             if( !DELTAT->step )
  68.             {
  69.                 DELTAT->flag = 0;
  70.                 DELTAT->portstate = 0x00;
  71.             }
  72.             /**** PCM memory check & limit check ****/
  73.             if(DELTAT->memory == 0){            // Check memory Mapped
  74.                 //Log(LOG_ERR,"YM Delta-T ADPCM rom not mapped\n");
  75.                 DELTAT->flag = 0;
  76.                 DELTAT->portstate = 0x00;
  77.                 //logerror("DELTAT memory 0\n");
  78.             }else{
  79.                 if( DELTAT->end >= DELTAT->memory_size )
  80.                 {        // Check End in Range
  81.                     //Log(LOG_ERR,"YM Delta-T ADPCM end out of range: $%08x\n",DELTAT->end);
  82.                     DELTAT->end = DELTAT->memory_size - 1;
  83.                     //logerror("DELTAT end over\n");
  84.                 }
  85.                 if( DELTAT->start >= DELTAT->memory_size )
  86.                 {        // Check Start in Range
  87.                     //Log(LOG_ERR,"YM Delta-T ADPCM start out of range: $%08x\n",DELTAT->start);
  88.                     DELTAT->flag = 0;
  89.                     DELTAT->portstate = 0x00;
  90.                     //logerror("DELTAT start under\n");
  91.                 }
  92.             }
  93.         } else if( v&0x01 ){
  94.             DELTAT->flag = 0;
  95.             DELTAT->portstate = 0x00;
  96.         }
  97.         break;
  98.     case 0x01:    /* L,R,-,-,SAMPLE,DA/AD,RAMTYPE,ROM */
  99.         DELTAT->portcontrol = v&0xff;
  100.         DELTAT->pan = &DELTAT->output_pointer[(v>>6)&0x03];
  101.         break;
  102.     case 0x02:    /* Start Address L */
  103.     case 0x03:    /* Start Address H */
  104.         DELTAT->start  = (DELTAT->reg[0x3]*0x0100 | DELTAT->reg[0x2]) << DELTAT->portshift;
  105.         break;
  106.     case 0x04:    /* Stop Address L */
  107.     case 0x05:    /* Stop Address H */
  108.         DELTAT->end    = (DELTAT->reg[0x5]*0x0100 | DELTAT->reg[0x4]) << DELTAT->portshift;
  109.         DELTAT->end   += (1<<DELTAT->portshift) - 1;
  110.         break;
  111.     case 0x06:    /* Prescale L (PCM and Recoard frq) */
  112.     case 0x07:    /* Proscale H */
  113.     case 0x08:    /* ADPCM data */
  114.       break;
  115.     case 0x09:    /* DELTA-N L (ADPCM Playback Prescaler) */
  116.     case 0x0a:    /* DELTA-N H */
  117.         DELTAT->delta  = (DELTAT->reg[0xa]*0x0100 | DELTAT->reg[0x9]);
  118.         DELTAT->step     = (UINT32)((double)(DELTAT->delta*(1<<(YM_DELTAT_SHIFT-16)))*(DELTAT->freqbase));
  119.         DELTAT->volume_w_step = (double)DELTAT->volume * DELTAT->step / (1<<YM_DELTAT_SHIFT);
  120.         break;
  121.     case 0x0b:    /* Level control (volume , voltage flat) */
  122.         {
  123.             INT32 oldvol = DELTAT->volume;
  124.             DELTAT->volume = (v&0xff)*(DELTAT->output_range/256) / YM_DELTAT_DECODE_RANGE;
  125.             if( oldvol != 0 )
  126.             {
  127.                 DELTAT->adpcml      = (int)((double)DELTAT->adpcml      / (double)oldvol * (double)DELTAT->volume);
  128.                 DELTAT->sample_step = (int)((double)DELTAT->sample_step / (double)oldvol * (double)DELTAT->volume);
  129.             }
  130.             DELTAT->volume_w_step = (int)((double)DELTAT->volume * (double)DELTAT->step / (double)(1<<YM_DELTAT_SHIFT));
  131.         }
  132.         break;
  133.     }
  134. }
  135.  
  136. void YM_DELTAT_ADPCM_Reset(YM_DELTAT *DELTAT,int pan)
  137. {
  138.     DELTAT->now_addr  = 0;
  139.     DELTAT->now_step  = 0;
  140.     DELTAT->step      = 0;
  141.     DELTAT->start     = 0;
  142.     DELTAT->end       = 0;
  143.     /* F2610->adpcm[i].delta     = 21866; */
  144.     DELTAT->volume    = 0;
  145.     DELTAT->pan       = &DELTAT->output_pointer[pan];
  146.     /* DELTAT->flagMask  = 0; */
  147.     DELTAT->arrivedFlag = 0;
  148.     DELTAT->flag      = 0;
  149.     DELTAT->adpcmx    = 0;
  150.     DELTAT->adpcmd    = 127;
  151.     DELTAT->adpcml    = 0;
  152.     /*DELTAT->adpcmm    = 0;*/
  153.     DELTAT->volume_w_step = 0;
  154.     DELTAT->next_leveling = 0;
  155.     DELTAT->portstate = 0;
  156.     /* DELTAT->portshift = 8; */
  157. }
  158.  
  159. #else /* YM_INLINE_BLOCK */
  160.  
  161. /* ---------- inline block ---------- */
  162.  
  163. /* DELTA-T particle adjuster */
  164. #define YM_DELTAT_DELTA_MAX (24576)
  165. #define YM_DELTAT_DELTA_MIN (127)
  166. #define YM_DELTAT_DELTA_DEF (127)
  167.  
  168. #define YM_DELTAT_DECODE_RANGE 32768
  169. #define YM_DELTAT_DECODE_MIN (-(YM_DELTAT_DECODE_RANGE))
  170. #define YM_DELTAT_DECODE_MAX ((YM_DELTAT_DECODE_RANGE)-1)
  171.  
  172. extern const INT32 ym_deltat_decode_tableB1[];
  173. extern const INT32 ym_deltat_decode_tableB2[];
  174.  
  175. #define YM_DELTAT_Limit(val,max,min)    \
  176. {                                        \
  177.     if ( val > max ) val = max;            \
  178.     else if ( val < min ) val = min;    \
  179. }
  180.  
  181. /**** ADPCM B (Delta-T control type) ****/
  182. INLINE void YM_DELTAT_ADPCM_CALC(YM_DELTAT *DELTAT)
  183. {
  184.     UINT32 step;
  185.     int data;
  186.     INT32 old_m;
  187.     INT32 now_leveling;
  188.     INT32 delta_next;
  189.  
  190.     DELTAT->now_step += DELTAT->step;
  191.     if ( DELTAT->now_step >= (1<<YM_DELTAT_SHIFT) )
  192.     {
  193.         step = DELTAT->now_step >> YM_DELTAT_SHIFT;
  194.         DELTAT->now_step &= (1<<YM_DELTAT_SHIFT)-1;
  195.         do{
  196.             if ( DELTAT->now_addr > (DELTAT->end<<1) ) {
  197.                 if( DELTAT->portstate&0x10 ){
  198.                     /**** repeat start ****/
  199.                     DELTAT->now_addr = DELTAT->start<<1;
  200.                     DELTAT->adpcmx   = 0;
  201.                     DELTAT->adpcmd   = YM_DELTAT_DELTA_DEF;
  202.                     DELTAT->next_leveling = 0;
  203.                     DELTAT->flag     = 1;
  204.                 }else{
  205.                     DELTAT->arrivedFlag |= DELTAT->flagMask;
  206.                     DELTAT->flag = 0;
  207.                     DELTAT->adpcml = 0;
  208.                     now_leveling = 0;
  209.                     return;
  210.                 }
  211.             }
  212.             if( DELTAT->now_addr&1 ) data = DELTAT->now_data & 0x0f;
  213.             else
  214.             {
  215.                 DELTAT->now_data = *(ym_deltat_memory+(DELTAT->now_addr>>1));
  216.                 data = DELTAT->now_data >> 4;
  217.             }
  218.             DELTAT->now_addr++;
  219.             /* shift Measurement value */
  220.             old_m      = DELTAT->adpcmx/*adpcmm*/;
  221.             /* ch->adpcmm = YM_DELTAT_Limit( ch->adpcmx + (decode_tableB3[data] * ch->adpcmd / 8) ,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN ); */
  222.             /* Forecast to next Forecast */
  223.             DELTAT->adpcmx += (ym_deltat_decode_tableB1[data] * DELTAT->adpcmd / 8);
  224.             YM_DELTAT_Limit(DELTAT->adpcmx,YM_DELTAT_DECODE_MAX, YM_DELTAT_DECODE_MIN);
  225.             /* delta to next delta */
  226.             DELTAT->adpcmd = (DELTAT->adpcmd * ym_deltat_decode_tableB2[data] ) / 64;
  227.             YM_DELTAT_Limit(DELTAT->adpcmd,YM_DELTAT_DELTA_MAX, YM_DELTAT_DELTA_MIN );
  228.             /* shift leveling value */
  229.             delta_next        = DELTAT->adpcmx/*adpcmm*/ - old_m;
  230.             now_leveling      = DELTAT->next_leveling;
  231.             DELTAT->next_leveling = old_m + (delta_next / 2);
  232.         }while(--step);
  233. //#define YM_DELTAT_CUT_RE_SAMPLING
  234. #ifdef YM_DELTAT_CUT_RE_SAMPLING
  235.         DELTAT->adpcml  = DELTAT->next_leveling * DELTAT->volume;
  236.         DELTAT->adpcml  = DELTAT->adpcmx/*adpcmm*/ * DELTAT->volume;
  237.     }
  238. #else
  239.         /* delta step of re-sampling */
  240.         DELTAT->sample_step = (DELTAT->next_leveling - now_leveling) * DELTAT->volume_w_step;
  241.         /* output of start point */
  242.         DELTAT->adpcml  = now_leveling * DELTAT->volume;
  243.         /* adjust to now */
  244.         DELTAT->adpcml += (int)((double)DELTAT->sample_step * ((double)DELTAT->now_step/(double)DELTAT->step));
  245.     }
  246.     DELTAT->adpcml += DELTAT->sample_step;
  247. #endif
  248.     /* output for work of output channels (outd[OPNxxxx])*/
  249.     *(DELTAT->pan) += DELTAT->adpcml;
  250. }
  251.  
  252. #endif /* YM_INLINE_BLOCK */
  253.